home *** CD-ROM | disk | FTP | other *** search
/ Collection of Internet / Collection of Internet.iso / infosrvr / dev / scott / WWW / NextStep / Implementation / old / HTParse.c < prev    next >
C/C++ Source or Header  |  1991-06-27  |  8KB  |  306 lines

  1. /*        Parse HyperText Document Address        HTParse.c
  2. **        ================================
  3. */
  4.  
  5. #include "HTUtils.h"
  6. #include "HTParse.h"
  7. #include "tcp.h"    /* For string only */
  8.  
  9. struct struct_parts {
  10.     char * access;
  11.     char * host;
  12.     char * absolute;
  13.     char * relative;
  14.     char * anchor;
  15. };
  16.  
  17.  
  18. /*    Strip white space off a string
  19. **    ------------------------------
  20. **
  21. ** On exit,
  22. **    Return value points to first non-white character, or to 0 if none.
  23. **    All trailing white space is OVERWRITTEN with zero.
  24. */
  25.  
  26. #ifdef __STDC__
  27. char * HTStrip(char * s)
  28. #else
  29. char * HTStrip(s)
  30.     char *s;
  31. #endif
  32. {
  33. #define SPACE(c) ((c==' ')||(c=='\t')||(c=='\n')) 
  34.     char * p=s;
  35.     for(p=s;*p;p++);                /* Find end of string */
  36.     for(p--;p>=s;p--) {
  37.         if(SPACE(*p)) *p=0;    /* Zap trailing blanks */
  38.     else break;
  39.     }
  40.     while(SPACE(*s))s++;    /* Strip leading blanks */
  41.     return s;
  42. }
  43.  
  44.  
  45. /*    Scan a filename for its consituents
  46. **    -----------------------------------
  47. **
  48. ** On entry,
  49. **    name    points to a document name which may be incomplete.
  50. ** On exit,
  51. **      absolute or relative may be nonzero (but not both).
  52. **    host, anchor and access may be nonzero if they were specified.
  53. **    Any which are nonzero point to zero terminated strings.
  54. */
  55. #ifdef __STDC__
  56. PRIVATE void scan(char * name, struct struct_parts *parts)
  57. #else
  58. PRIVATE void scan(name, parts)
  59.     char * name;
  60.     struct struct_parts *parts;
  61. #endif
  62. {
  63.     char * after_access;
  64.     char * p;
  65.     int length = strlen(name);
  66.     
  67.     parts->access = 0;
  68.     parts->host = 0;
  69.     parts->absolute = 0;
  70.     parts->relative = 0;
  71.     parts->anchor = 0;
  72.     
  73.     after_access = name;
  74.     for(p=name; *p; p++) {
  75.     if (*p==':') {
  76.         *p = 0;
  77.         parts->access = name;    /* Access name has been specified */
  78.         after_access = p+1;
  79.     }
  80.     if (*p=='/') break;
  81.     if (*p=='#') break;
  82.     }
  83.     
  84.     for(p=name+length-1; p>=name; p--) {
  85.     if (*p =='#') {
  86.         parts->anchor=p+1;
  87.         *p=0;                /* terminate the rest */
  88.     }
  89.     }
  90.     p = after_access;
  91.     if (*p=='/'){
  92.     if (p[1]=='/') {
  93.         parts->host = p+2;        /* host has been specified     */
  94.         *p=0;            /* Terminate access         */
  95.         p=strchr(parts->host,'/');    /* look for end of host name if any */
  96.         if(p) {
  97.             *p=0;            /* Terminate host */
  98.             parts->absolute = p+1;        /* Root has been found */
  99.         }
  100.     } else {
  101.         parts->absolute = p+1;        /* Root found but no host */
  102.     }        
  103.     } else {
  104.         parts->relative = (*after_access) ? after_access : 0;    /* zero for "" */
  105.     }
  106. } /*scan */    
  107.  
  108.  
  109. /*    Parse a Name relative to another name
  110. **    -------------------------------------
  111. **
  112. **    This returns those parts of a name which are given (and requested)
  113. **    substituting bits from the realted name where necessary.
  114. **
  115. ** On entry,
  116. **    aName        A filename given
  117. **      relatedName     A name relative to which aName is to be parsed
  118. **      wanted          A mask for the bits which are wanted.
  119. **
  120. ** On exit,
  121. **    returns        A pointer to a malloc'd string which MUST BE FREED
  122. */
  123. #ifdef __STDC__
  124. char * HTParse(const char * aName, const char * relatedName, int wanted)
  125. #else
  126. char * HTParse(aName, relatedName, wanted)
  127.     char * aName;
  128.     char * relatedName;
  129.     int wanted;
  130. #endif
  131.  
  132. {
  133.     char * result = 0;
  134.     char * return_value = 0;
  135.     int len;
  136.     char * name = 0;
  137.     char * rel = 0;
  138.     char * p;
  139.     struct struct_parts given, related;
  140.     
  141.     /* Make working copies of input strings to cut up:
  142.     */
  143.     len = strlen(aName)+strlen(relatedName)+10;
  144.     result=(char *)malloc(len);        /* Lots of space: more than enough */
  145.     
  146.     StrAllocCopy(name, aName);
  147.     StrAllocCopy(rel, relatedName);
  148.     
  149.     scan(name, &given);
  150.     scan(rel,  &related); 
  151.     result[0]=0;        /* Clear string  */
  152.     if (wanted & PARSE_ACCESS)
  153.         if (given.access|| related.access) {
  154.         strcat(result, given.access ? given.access : related.access);
  155.         if(wanted & PARSE_PUNCTUATION) strcat(result, ":");
  156.     }
  157.     
  158.     if (given.access && related.access)    /* If different, inherit nothing. */
  159.         if (strcmp(given.access, related.access)!=0) {
  160.         related.host=0;
  161.         related.absolute=0;
  162.         related.relative=0;
  163.         related.anchor=0;
  164.     }
  165.     
  166.     if (wanted & PARSE_HOST)
  167.         if(given.host || related.host) {
  168.         if(wanted & PARSE_PUNCTUATION) strcat(result, "//");
  169.         strcat(result, given.host ? given.host : related.host);
  170.     }
  171.     
  172.     if (wanted & PARSE_PATH) {
  173.         if(given.absolute) {                /* All is given */
  174.         if(wanted & PARSE_PUNCTUATION) strcat(result, "/");
  175.         strcat(result, given.absolute);
  176.     } else if(related.absolute) {    /* Adopt path not name */
  177.         strcat(result, "/");
  178.         strcat(result, related.absolute);
  179.         if (given.relative) {
  180.         for (p=result+strlen(result)-1; *p!='/'; p--);    /* last / */
  181.         p[1]=0;                    /* Remove filename */
  182.         strcat(result, given.relative);        /* Add given one */
  183.         }
  184.     } else if(given.relative) {
  185.         strcat(result, given.relative);        /* what we've got */
  186.     } else if(related.relative) {
  187.         strcat(result, related.relative);
  188.     }
  189.     }
  190.         
  191.     if (wanted & PARSE_ANCHOR)
  192.         if(given.anchor || related.anchor) {
  193.         if(wanted & PARSE_PUNCTUATION) strcat(result, "#");
  194.         strcat(result, given.anchor ? given.anchor : related.anchor);
  195.     }
  196.     free(rel);
  197.     free(name);
  198.     
  199.     StrAllocCopy(return_value, result);
  200.     free(result);
  201.     return return_value;        /* exactly the right length */
  202. }
  203.  
  204. /*            Simplify a filename
  205. //        -------------------
  206. //
  207. // A unix-style file is allowed to contain the seqeunce xxx/../ which may be
  208. // replaced by "" , and the seqeunce "/./" which may be replaced by "/".
  209. // Simplification helps us recognize duplicate filenames.
  210. //
  211. //    Thus,     /etc/junk/../fred     becomes    /etc/fred
  212. //        /etc/junk/./fred    becomes    /etc/junk/fred
  213. */
  214. #ifdef __STDC__
  215. void HTSimplify(char * filename)
  216. #else
  217. void HTSimplify(filename)
  218.     char * filename;
  219. #endif
  220.  
  221. {
  222.     char * p;
  223.     char * q;
  224.     for(p=filename+2; *p; p++) {
  225.         if (*p=='/') {
  226.         if ((p[1]=='.') && (p[2]=='.') && (p[3]=='/')) {
  227.         for (q=p-1; (q>filename) && (*q!='/'); q--);    /* last / */
  228.         if (*q=='/') {
  229.                 strcpy(q+1, p+4);        /* Remove  xxx/../    */
  230.             p = q-1;        /* Start again with last slash */
  231.         } else {
  232.             strcpy(filename, p+4);    /* remove  xxx/../    */
  233.             p = filename;        /* Start again */
  234.         }
  235.         } else if ((p[1]=='.') && (p[2]=='/')) {
  236.             strcpy(p, p+2);            /* Remove a slash and a dot */
  237.         }
  238.     }
  239.     }
  240. }
  241.  
  242.  
  243. /*        Make Relative Name
  244. **        ------------------
  245. **
  246. ** This function creates and returns a string which gives an expression of
  247. ** one address as related to another. Where there is no relation, an absolute
  248. ** address is retured.
  249. **
  250. **  On entry,
  251. **    Both names must be absolute, fully qualified names of nodes
  252. **    (no anchor bits)
  253. **
  254. **  On exit,
  255. **    The return result points to a newly allocated name which, if
  256. **    parsed by HTParse relative to relatedName, will yield aName.
  257. **    The caller is responsible for freeing the resulting name later.
  258. **
  259. */
  260. #ifdef __STDC__
  261. char * HTRelative(const char * aName, const char *relatedName)
  262. #else
  263. char * HTRelative(aName, relatedName)
  264.    char * aName;
  265.    char * relatedName;
  266. #endif
  267. {
  268.     char * result = 0;
  269.     CONST char *p = aName;
  270.     CONST char *q = relatedName;
  271.     CONST char * after_access = 0;
  272.     CONST char * path = 0;
  273.     CONST char * last_slash = 0;
  274.     int slashes = 0;
  275.     
  276.     for(;*p; p++, q++) {    /* Find extent of match */
  277.         if (*p!=*q) break;
  278.     if (*p==':') after_access = p+1;
  279.     if (*p=='/') {
  280.         last_slash = p;
  281.         slashes++;
  282.         if (slashes==3) path=p;
  283.     }
  284.     }
  285.     
  286.     /* q, p point to the first non-matching character or zero */
  287.     
  288.     if (!after_access) {            /* Different access */
  289.         StrAllocCopy(result, aName);
  290.     } else if (slashes<3){            /* Different nodes */
  291.         StrAllocCopy(result, after_access);
  292.     } else if (slashes==3){            /* Same node, different path */
  293.         StrAllocCopy(result, path);
  294.     } else {                    /* Some path in common */
  295.         int levels= 0;
  296.         for(; *q && (*q!='#'); q++)  if (*q=='/') levels++;
  297.     result = (char *)malloc(3*levels + strlen(last_slash) + 1);
  298.     result[0]=0;
  299.     for(;levels; levels--)strcat(result, "../");
  300.     strcat(result, last_slash+1);
  301.     }
  302.     if (TRACE) printf("HT: `%s' expressed relative to\n    `%s' is\n   `%s'.",
  303.             aName, relatedName, result);
  304.     return result;
  305. }
  306.